#include "irq.h"
#include "cpu_instr.h"
#include "log.h"
#include "task.h"
void dump_core_regs(exception_frame_t *frame)
{
    uint32_t ss;
    uint32_t esp;
    if (frame->cs & 0x3)
    {
        ss  = frame->ss3;
        esp = frame->esp3;
    }
    else
    {
        ss  = frame->ds;
        esp = frame->esp;
    }
    log_printf("IRQ_num:%d, error_code:%d", frame->num, frame->error_code);
    log_printf("GS:%x, FS:%x, ES:%x, ss:%x", frame->gs, frame->fs, frame->es, ss);
    log_printf("EAX:%x, ECX:%x, EDX:%x, EBX:%x", frame->eax, frame->ecx, frame->edx, frame->ebx);
    log_printf("eip: %x, cs: %x, eflags: %x", frame->eip, frame->cs, frame->eflags);
    log_printf("esp:%x", esp);
}
void do_default_handler(exception_frame_t *frame, char *message)
{
    log_printf("IRQ/Exception happend:%s", message);
    dump_core_regs(frame);
    if (frame->cs & 0x3)
    {
        sys_exit(frame->error_code);
    }
    else
    {
        while (1)
        {
            hlt();
        }
    }
}
void do_handler_unknown(exception_frame_t *frame)
{
    do_default_handler(frame, "unknown exception");
}
void do_handler_divide_error(exception_frame_t *frame)
{
    do_default_handler(frame, "divide exception");
}
void do_handler_debug(exception_frame_t *frame)
{
    do_default_handler(frame, "debug exception");
}
void do_handler_nmi(exception_frame_t *frame)
{
    do_default_handler(frame, "nmi exception");
}
void do_handler_breakpoint(exception_frame_t *frame)
{
    do_default_handler(frame, "breakpoint exception");
}
void do_handler_overflow(exception_frame_t *frame)
{
    do_default_handler(frame, "overflow exception");
}
void do_handler_bound_range_exceeded(exception_frame_t *frame)
{
    do_default_handler(frame, "bound range exceeded exception");
}
void do_handler_invalid_opcode(exception_frame_t *frame)
{
    do_default_handler(frame, "invalid opcode exception (Undefined Opcode)");
}
void do_handler_device_not_available(exception_frame_t *frame)
{
    do_default_handler(frame, "device not available exception");
}
void do_handler_double_fault(exception_frame_t *frame)
{
    do_default_handler(frame, "double fault exception");
}
void do_handler_invalid_tss(exception_frame_t *frame)
{
    do_default_handler(frame, "invalid tss exception");
}
void do_handler_segment_not_present(exception_frame_t *frame)
{
    do_default_handler(frame, "segment not present exception");
}
void do_handler_stack_segment_fault(exception_frame_t *frame)
{
    do_default_handler(frame, "stack segment fault exception");
}
void do_handler_general_protection_fault(exception_frame_t *frame)
{
    log_printf("------------------");
    log_printf("general protection fault");
    if (frame->error_code & ERR_EXT)
    {
        log_printf("the exception occurred during delivery of an event external to the program, such as an interrupt "
                   "or an earlier exception. %x",
                   read_cr2());
    }
    else
    {
        log_printf("the exception occurred during delivery of a software interrupt (INT n, INT3, or INTO) %x",
                   read_cr2());
    }
    if (frame->error_code & ERR_IDT)
    {
        log_printf("the index portion of the error code refers to a gate descriptor in the IDT; %x", read_cr2());
    }
    else
    {
        log_printf("the index refers to a descriptor in the GDT or the current LDT. %x", read_cr2());
    }
    log_printf("selector index: %x", frame->error_code & 0xfff8);
    dump_core_regs(frame);
    if (frame->cs & 0x3)
    {
        sys_exit(frame->error_code);
    }
    else
    {
        while (1)
        {
            hlt();
        }
    }
}
void do_handler_page_fault(exception_frame_t *frame)
{
    log_printf("------------------");
    log_printf("page fault");
    if (frame->error_code & ERR_PAGE_P)
    {
        log_printf("The fault was caused by a page-level protection violation. %x", read_cr2());
    }
    else
    {
        log_printf("The fault was caused by a non-present page. %x", read_cr2());
    }
    if (frame->error_code & ERR_PAGE_WR)
    {
        log_printf("The access causing the fault was a write. %x", read_cr2());
    }
    else
    {
        log_printf("The access causing the fault was a read.%x", read_cr2());
    }
    if (frame->error_code & ERR_PAGE_US)
    {
        log_printf("A user-mode access caused the fault %x", read_cr2());
    }
    else
    {
        log_printf("A supervisor-mode access caused the fault. %x", read_cr2());
    }
    dump_core_regs(frame);
    if (frame->cs & 0x3)
    {
        sys_exit(frame->error_code);
    }
    else
    {
        while (1)
        {
            hlt();
        }
    }
}
void do_handler_fpu_fault(exception_frame_t *frame)
{
    do_default_handler(frame, "x87 fpu floating point fault exception");
}
void do_handler_alignment_check(exception_frame_t *frame)
{
    do_default_handler(frame, "alignment check exception");
}
void do_handler_machine_check(exception_frame_t *frame)
{
    do_default_handler(frame, "machine check exception");
}
void do_handler_simd_floating_point(exception_frame_t *frame)
{
    do_default_handler(frame, "simd floating point exception");
}
void do_handler_virtualization(exception_frame_t *frame)
{
    do_default_handler(frame, "virtualization exception");
}
void do_handler_control_protection(exception_frame_t *frame)
{
    do_default_handler(frame, "control protection exception");
}